home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src890906.arc / UDP.C < prev    next >
C/C++ Source or Header  |  1989-09-07  |  8KB  |  309 lines

  1. /* Send and receive User Datagram Protocol packets */
  2. #include "global.h"
  3. #include "mbuf.h"
  4. #include "netuser.h"
  5. #include "udp.h"
  6. #include "ip.h"
  7. #include "internet.h"
  8. #include "icmp.h"
  9.  
  10. static struct udp_cb *lookup_udp __ARGS((struct socket *socket));
  11. static int16 hash_udp __ARGS((struct socket *socket));
  12.  
  13. /* Hash table for UDP structures */
  14. struct udp_cb *Udps[NUDP] = { NULLUDP} ;
  15. struct udp_stat Udp_stat;    /* Statistics */
  16.  
  17. /* Create a UDP control block for lsocket, so that we can queue
  18.  * incoming datagrams.
  19.  */
  20. struct udp_cb *
  21. open_udp(lsocket,r_upcall)
  22. struct socket *lsocket;
  23. void (*r_upcall)();
  24. {
  25.     register struct udp_cb *up;
  26.     int16 hval; 
  27.  
  28.     if((up = lookup_udp(lsocket)) != NULLUDP)
  29.         return up;    /* Already exists */
  30.     if((up = (struct udp_cb *)calloc(1,sizeof (struct udp_cb))) == NULLUDP){
  31.         Net_error = NO_MEM;
  32.         return NULLUDP;
  33.     }
  34.     up->socket.address = lsocket->address;
  35.     up->socket.port = lsocket->port;
  36.     up->r_upcall = r_upcall;
  37.  
  38.     hval = hash_udp(lsocket);
  39.     up->next = Udps[hval];
  40.     if(up->next != NULLUDP)
  41.         up->next->prev = up;
  42.     Udps[hval] = up;
  43.     return up;
  44. }
  45.  
  46. /* Send a UDP datagram */
  47. int
  48. send_udp(lsocket,fsocket,tos,ttl,data,length,id,df)
  49. struct socket *lsocket;        /* Source socket */
  50. struct socket *fsocket;        /* Destination socket */
  51. char tos;            /* Type-of-service for IP */
  52. char ttl;            /* Time-to-live for IP */
  53. struct mbuf *data;        /* Data field, if any */
  54. int16 length;            /* Length of data field */
  55. int16 id;            /* Optional ID field for IP */
  56. char df;            /* Don't Fragment flag for IP */
  57. {
  58.     struct mbuf *bp;
  59.     struct pseudo_header ph;
  60.     struct udp udp;
  61.  
  62.     length = UDPHDR;
  63.     if(data != NULLBUF)
  64.         length += len_mbuf(data);
  65.  
  66.     udp.source = lsocket->port;
  67.     udp.dest = fsocket->port;
  68.     udp.length = length;
  69.  
  70.     /* Create IP pseudo-header, compute checksum and send it */
  71.     ph.length = length;
  72.     ph.source = lsocket->address;
  73.     ph.dest = fsocket->address;
  74.     ph.protocol = UDP_PTCL;
  75.  
  76.     if((bp = htonudp(&udp,data,&ph)) == NULLBUF){
  77.         Net_error = NO_MEM;
  78.         free_p(data);
  79.         return 0;
  80.     }
  81.     Udp_stat.sent++;
  82.     ip_send(lsocket->address,fsocket->address,UDP_PTCL,tos,ttl,bp,length,id,df);
  83.     return length;
  84. }
  85. /* Accept a waiting datagram, if available. Returns length of datagram */
  86. int
  87. recv_udp(up,fsocket,bp)
  88. register struct udp_cb *up;
  89. struct socket *fsocket;        /* Place to stash incoming socket */
  90. struct mbuf **bp;        /* Place to stash data packet */
  91. {
  92.     struct socket *sp;
  93.     struct mbuf *buf;
  94.     int16 length;
  95.  
  96.     if(up == NULLUDP){
  97.         Net_error = NO_CONN;
  98.         return -1;
  99.     }
  100.     if(up->rcvcnt == 0){
  101.         Net_error = WOULDBLK;
  102.         return -1;
  103.     }
  104.     buf = dequeue(&up->rcvq);
  105.     up->rcvcnt--;
  106.  
  107.     sp = (struct socket *)buf->data;
  108.     /* Fill in the user's foreign socket structure, if given */
  109.     if(fsocket != NULLSOCK){
  110.         fsocket->address = sp->address;
  111.         fsocket->port = sp->port;
  112.     }
  113.     /* Strip socket header and hand data to user */
  114.     pullup(&buf,NULLCHAR,sizeof(struct socket));
  115.     length = len_mbuf(buf);
  116.     if(bp != (struct mbuf **)NULL)
  117.         *bp = buf;
  118.     else
  119.         free_p(buf);
  120.     return length;
  121. }
  122. /* Delete a UDP control block */
  123. int
  124. del_udp(up)
  125. struct udp_cb *up;
  126. {
  127.     struct mbuf *bp;
  128.     int16 hval;
  129.  
  130.     if(up == NULLUDP){
  131.         Net_error = INVALID;
  132.         return -1;
  133.     }        
  134.     /* Get rid of any pending packets */
  135.     while(up->rcvcnt != 0){
  136.         bp = up->rcvq;
  137.         up->rcvq = up->rcvq->anext;
  138.         free_p(bp);
  139.         up->rcvcnt--;
  140.     }
  141.     hval = hash_udp(&up->socket);
  142.     if(up->prev == NULLUDP)
  143.         Udps[hval] = up->next;        /* First on list */
  144.     else
  145.         up->prev->next = up->next;
  146.     if(up->next != NULLUDP)
  147.         up->next->prev = up->prev;
  148.  
  149.     free((char *)up);
  150.     return 0;
  151. }
  152. /* Process an incoming UDP datagram */
  153. void
  154. udp_input(iface,bp,ip,rxbroadcast)
  155. struct iface *iface;    /* Input interface */
  156. struct mbuf *bp;    /* UDP header and data */
  157. struct ip *ip;        /* IP header */
  158. int rxbroadcast;    /* The only protocol that accepts 'em */
  159. {
  160.     struct pseudo_header ph;
  161.     struct udp udp;
  162.     struct udp_cb *up;
  163.     struct socket lsocket;
  164.     struct socket *fsocket;
  165.     struct mbuf *packet;
  166.     int ckfail = 0;
  167.     int16 length;
  168.  
  169.     if(bp == NULLBUF)
  170.         return;
  171.  
  172.     Udp_stat.rcvd++;
  173.  
  174.     /* Create pseudo-header and verify checksum */
  175.     ph.source = ip->source;
  176.     ph.dest = ip->dest;
  177.     ph.protocol = ip->protocol;
  178.     length = ip->length - IPLEN - ip->optlen;
  179.     ph.length = length;
  180.  
  181.     if(cksum(&ph,bp,length) != 0)
  182.         /* Checksum apparently failed, note for later */
  183.         ckfail++;
  184.  
  185.     /* Extract UDP header in host order */
  186.     ntohudp(&udp,&bp);
  187.  
  188.     /* If the checksum field is zero, then ignore a checksum error.
  189.      * I think this is dangerously wrong, but it is in the spec.
  190.      */
  191.     if(ckfail && udp.checksum != 0){
  192.         Udp_stat.cksum++;
  193.         free_p(bp);
  194.         return;
  195.     }
  196.     /* If this was a broadcast packet, pretend it was sent to us */
  197.     if(rxbroadcast){
  198.         lsocket.address = Ip_addr;
  199.         Udp_stat.bdcsts++;
  200.     } else
  201.         lsocket.address = ip->dest;
  202.  
  203.     lsocket.port = udp.dest;
  204.     /* See if there's somebody around to read it */
  205.     if((up = lookup_udp(&lsocket)) == NULLUDP){
  206.         /* Nope, return an ICMP message */
  207.         Udp_stat.unknown++;
  208.         if(!rxbroadcast){
  209.             bp = htonudp(&udp,bp,&ph);
  210.             icmp_output(ip,bp,DEST_UNREACH,PORT_UNREACH,NULL);
  211.         }
  212.         free_p(bp);
  213.         return;
  214.     }
  215.     /* Create space for the foreign socket info */
  216.     if((packet = pushdown(bp,sizeof(struct socket))) == NULLBUF){
  217.         /* No space, drop whole packet */
  218.         free_p(bp);
  219.         return;
  220.     }
  221.     fsocket = (struct socket *)packet->data;
  222.     fsocket->address = ip->source;
  223.     fsocket->port = udp.source;
  224.  
  225.     /* Queue it */
  226.     enqueue(&up->rcvq,packet);
  227.     up->rcvcnt++;
  228.     if(up->r_upcall)
  229.         (*up->r_upcall)(iface,up,up->rcvcnt);
  230. }
  231. /* Look up UDP socket, return control block pointer or NULLUDP if nonexistant */
  232. static
  233. struct udp_cb *
  234. lookup_udp(socket)
  235. struct socket *socket;
  236. {
  237.     register struct udp_cb *up;
  238.  
  239.     up = Udps[hash_udp(socket)];
  240.     while(up != NULLUDP){
  241.         if(memcmp((char *)socket,(char *)&up->socket,sizeof(struct socket)) == 0)
  242.             break;
  243.         up = up->next;
  244.     }
  245.     return up;
  246. }
  247.  
  248. /* Hash a UDP socket (address and port) structure */
  249. static
  250. int16
  251. hash_udp(socket)
  252. struct socket *socket;
  253. {
  254.     register unsigned int hval;
  255.  
  256.     /* Compute hash function on socket structure */
  257.     hval = hiword(socket->address);
  258.     hval ^= loword(socket->address);
  259.     hval ^= socket->port;
  260.     return hval % NUDP;
  261. }
  262. /* Convert UDP header in internal format to an mbuf in external format */
  263. struct mbuf *
  264. htonudp(udp,data,ph)
  265. struct udp *udp;
  266. struct mbuf *data;
  267. struct pseudo_header *ph;
  268. {
  269.     struct mbuf *bp;
  270.     register char *cp;
  271.     int16 checksum;
  272.  
  273.     /* Allocate UDP protocol header and fill it in */
  274.     if((bp = pushdown(data,UDPHDR)) == NULLBUF)
  275.         return NULLBUF;
  276.  
  277.     cp = bp->data;
  278.     cp = put16(cp,udp->source);    /* Source port */
  279.     cp = put16(cp,udp->dest);    /* Destination port */
  280.     cp = put16(cp,udp->length);    /* Length */
  281.     *cp++ = 0;            /* Clear checksum */
  282.     *cp-- = 0;
  283.  
  284.     /* All zeros and all ones is equivalent in one's complement arithmetic;
  285.      * the spec requires us to change zeros into ones to distinguish an
  286.       * all-zero checksum from no checksum at all
  287.      */
  288.     if((checksum = cksum(ph,bp,ph->length)) == 0)
  289.         checksum = 0xffffffff;
  290.     put16(cp,checksum);
  291.     return bp;
  292. }
  293. /* Convert UDP header in mbuf to internal structure */
  294. int
  295. ntohudp(udp,bpp)
  296. struct udp *udp;
  297. struct mbuf **bpp;
  298. {
  299.     char udpbuf[UDPHDR];
  300.  
  301.     if(pullup(bpp,udpbuf,UDPHDR) != UDPHDR)
  302.         return -1;
  303.     udp->source = get16(&udpbuf[0]);
  304.     udp->dest = get16(&udpbuf[2]);
  305.     udp->length = get16(&udpbuf[4]);
  306.     udp->checksum = get16(&udpbuf[6]);
  307.     return 0;
  308. }
  309.